#pragma once
#include "VLDST_OP_enum.h"
#include"../../execution_module/write_delay_control/write_delay_control.h"
#include "../../instruction_module/instruction.h"
#include "../LDST_mode_enum.h"
#include <iostream>

//TODO:确定如何判断寻址方式，并在ldst模块中确定所需的操作数
//VLDST模块主要功能为计算访存地址，通过解析指令中的mode，确定寻址方式，并通过传入数据计算出最终地址
//如果基址寄存器需要改动，则对其进行写入修改
class VLDST {
public:
    VLDST(V_memory* am, WriteControlModule* wcm, RegisterFile* rf) : AM(am), WCM(wcm), RF(rf) {

    }
    ~VLDST() {}

protected:
    V_memory* AM;
    WriteControlModule* WCM;
    RegisterFile* RF;

};

//VLDST0仅负责混洗操作中的模n读写操作，其余指令均由VLDST1执行
class VLDST_0 : public VLDST {
public:
    VLDST_0(V_memory* am, WriteControlModule* wcm, RegisterFile* rf) : VLDST(am, wcm, rf){

    }
    ~VLDST_0() {}
    void Execute(instruction* vldst_instr);
    inline uint64_t read_Reg(int reg_id);
    inline std::vector<uint64_t>* read_Vec_Reg(int reg_id);
    //op代表寻址计算的方式以及基址寄存器的操作，size代表访存粒度并决定地址的对齐粒度
    addr_size_t calculate_mem_addr(int AR_reg_id, int OR_reg_id, int op, int size);
    addr_size_t calculate_mem_addr(int AR_reg_id, uint64_t imm, int op, int size);
    void do_VLDDW0M2(addr_size_t addr, int dst_reg_id);
    void do_VLDDW0M4(addr_size_t addr, int dst_reg_id);
    void do_VSTDW0M16(addr_size_t addr, int src_reg_id);
    void do_VSTDW0M32(addr_size_t addr, int src_reg_id); 
};

class VLDST_1 : public VLDST_0 {
public:
    VLDST_1(V_memory* am, WriteControlModule* wcm, RegisterFile* rf) : VLDST_0(am, wcm, rf) {

    }
    ~VLDST_1() {}
    void Execute(instruction* vldst_instr);
    void do_VLDH(addr_size_t addr, int dst_reg_id);
    void do_VLDHU(addr_size_t addr, int dst_reg_id);
    void do_VSTH(addr_size_t addr, int src_reg_id);
    void do_VLDW(addr_size_t addr, int dst_reg_id);
    void do_VSTW(addr_size_t addr, int src_reg_id);
    void do_VLDDW(addr_size_t addr, int dst_reg_id);
    void do_VSTDW(addr_size_t addr, int src_reg_id);
    void do_VLDDWM2(addr_size_t addr, int dst_reg_id);
    void do_VSTDWM16(addr_size_t addr, int src_reg_id);
    void do_VLDDW1M2(addr_size_t addr, int dst_reg_id);
    void do_VLDDW1M4(addr_size_t addr, int dst_reg_id);
    void do_VSTDW1M16(addr_size_t addr, int src_reg_id);
    void do_VSTDW1M32(addr_size_t addr, int src_reg_id);

};